package com.zmn.oms.business.impl.conf.channel;


import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.aliyun.openservices.shade.org.apache.commons.lang3.math.NumberUtils;
import com.google.common.collect.Lists;
import com.zmn.account.common.utils.NumberUtil;
import com.zmn.base.channel.common.dro.ChannelDRO;
import com.zmn.base.channel.common.query.ChannelQuery;
import com.zmn.base.channel.dubbo.interfaces.channel.ChannelListRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.mcc.cas.web.StaffAdminService;
import com.zmn.oms.business.interfaces.conf.channel.ConfOrderChannelBService;
import com.zmn.oms.common.constant.ChannelConsts;
import com.zmn.oms.common.constant.RedisKeyConsts;
import com.zmn.oms.common.dro.conf.channel.ConfChannelWorkOrderTypeDRO;
import com.zmn.oms.common.dro.conf.channel.ConfOrderChannelDRO;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.model.entity.conf.channel.ConfOrderChannel;
import com.zmn.oms.model.entity.conf.channel.ConfOrderChannelQuery;
import com.zmn.oms.model.vo.conf.channel.ConfOrderChannelVO;
import com.zmn.oms.services.interfaces.conf.channel.ConfOrderChannelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 类描述: 渠道订单参数配置 逻辑处理实现类
 *
 * @author: liudi
 * @since: 2022/02/18 11:14
 */
@Slf4j
@Service
public class ConfOrderChannelBServiceImpl implements ConfOrderChannelBService {

	@Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION, check = false, timeout = 10000)
	protected ChannelListRemoteService channelListRemoteService;
	@Resource
	private ConfOrderChannelService confOrderChannelService;
	@Resource
	private RedisTemplate<String, String> redisTemplate;

	@Override
	public List<ConfOrderChannelVO> listPageByQuery(ConfOrderChannelQuery query) {
		Objects.requireNonNull(query);

		if (StringUtils.isNotBlank(query.getKeyWord())) {
			List<Integer> channelIds;

			if (NumberUtils.isDigits(query.getKeyWord())) {
				channelIds = Lists.newArrayList(Integer.valueOf(query.getKeyWord()));
			} else {
				query.setChannelName(query.getKeyWord());
				channelIds = this.getChannelIdsByChannelName(query);

				// 处理【渠道名称】 没查询到数据
				if (CollectionUtil.isNullOrEmpty(channelIds)) {
					return Lists.newArrayList();
				}
			}
			query.setChannelIds(channelIds);
		}

		List<ConfOrderChannel> confOrderChannels = confOrderChannelService.listPageByQuery(query);
		List<Integer> channelIds = confOrderChannels.stream().map(ConfOrderChannel::getChannelId).collect(Collectors.toList());

		ResponseDTO<List<ChannelDRO>> channelListDTO = channelListRemoteService.listByChannelIds(channelIds);
		List<ChannelDRO> channelListData = channelListDTO.getData();
		if (!channelListDTO.isSuccess() || CollectionUtils.isEmpty(channelListData)) {
			return Lists.newArrayList();
		}

		Map<Integer, ChannelDRO> channelMap = channelListData.stream().collect(Collectors.toMap(ChannelDRO::getChannelId, channelDRO -> channelDRO));

		List<ConfOrderChannelVO> voList = confOrderChannels.stream().map(confOrderChannel -> {
			// 组装VO 设置【渠道名称】 和 【渠道类型】
			ConfOrderChannelVO channelVO = BeanMapper.map(confOrderChannel, ConfOrderChannelVO.class);
			ChannelDRO channelDRO = channelMap.getOrDefault(confOrderChannel.getChannelId(), new ChannelDRO());
			channelVO.setChannelName(Objects.isNull(channelDRO.getName()) ? "" : channelDRO.getName());
			channelVO.setChannelTypeName(ChannelConsts.getChannelTypeName(NumberUtil.isNullOrZero(channelDRO.getChannelType()) ? 0 : channelDRO.getChannelType()));
			return channelVO;
		}).collect(Collectors.toList());

		return voList;
	}

	@Override
	public List<Integer> listChannelIdByHiddenStatus(Integer hiddenStatus) {
		if (NumberUtil.isNullOrZero(hiddenStatus)) {
			return Lists.newArrayList();
		}

		ConfOrderChannelQuery query = new ConfOrderChannelQuery();
		query.setHidden(hiddenStatus);

		return Optional.ofNullable(confOrderChannelService.listByQuery(query))
				.orElse(Lists.newArrayList())
				.stream()
				.map(ConfOrderChannel::getChannelId)
				.collect(Collectors.toList());
	}

	@Override
	public List<ConfOrderChannel> listConfOrderChannelByChannelIds(List<Integer> channelIds) {
		// log.info("根据渠道ID集合查询渠道订单配置 参数 channelIds：{}", channelIds);
		if (CollectionUtils.isEmpty(channelIds)) {
			return Lists.newArrayList();
		}

		ConfOrderChannelQuery query = new ConfOrderChannelQuery();
		query.setChannelIds(channelIds);
		List<ConfOrderChannel> confOrderChannelList = confOrderChannelService.listByQuery(query);

		if (CollectionUtils.isEmpty(confOrderChannelList)) {
			return Lists.newArrayList();
		}

		// log.info("根据渠道ID集合查询渠道订单配置 出参 confOrderChannelList：{}", confOrderChannelList);
		return confOrderChannelList;
	}

	@Override
	public boolean checkNotifyEngineer(Integer channelId) {
		ConfOrderChannel channelOrderConfig = confOrderChannelService.findByKey(channelId);

		// 如果 “二级渠道” 没有订单配置数据，则查询 “一级渠道” 的订单配置数据
		if (Objects.isNull(channelOrderConfig)) {
			ChannelDRO channelDRO = channelListRemoteService.getByChannelId(channelId).getData();

			if (log.isDebugEnabled()) {
				log.debug("ConfOrderChannelBService#checkNotifyEngineer 入参：[{}]，出参：{}", channelId, channelDRO);
			}

			if (Objects.equals(ChannelConsts.RANK_TWO, channelDRO.getRank())
					&& NumberUtil.isPositiveInteger(channelDRO.getParentId())) {
				channelOrderConfig = confOrderChannelService.findByKey(channelDRO.getParentId());
			}
		}

		if (Objects.isNull(channelOrderConfig)) {
			log.warn("根据渠道ID查询渠道订单配置失败，渠道ID：[{}]", channelId);
			return false;
		}

		return Objects.equals(GlobalConsts.YES, channelOrderConfig.getNotifyEngineer());
	}

	@Override
	public ConfOrderChannelDRO getByChannelId(Integer channelId) throws OmsBaseException {
		// log.info("ConfOrderChannelBServiceImpl#getByChannelId 入参 channelId：{}", channelId);
		String key = String.format(RedisKeyConsts.ORDER_CHANNEL_CONFIG_KEY, channelId);
		String value = redisTemplate.opsForValue().get(key);
		// 缓存中有数据
		if (StringUtil.isNotBlank(value)) {
			try {
				return JSONObject.parseObject(value, ConfOrderChannelDRO.class);
			} catch (Exception e) {
				throw new OmsBaseException(value);
			}
		}

		int time = 30;
		String lockKey = String.format(RedisKeyConsts.ORDER_CHANNEL_CONFIG_LOCK_KEY, channelId);
		DistributedLock redisLock = DistributedLockUtils.buildReentrantLock(lockKey, time);
		if (redisLock.tryLock()) {

			try {
				ConfOrderChannelDRO confOrderChannel = this.getByChannelIdDataBase(channelId);
				if (Objects.isNull(confOrderChannel)) {
					return null;
				}

				value = JSONObject.toJSONString(confOrderChannel);
				redisTemplate.opsForValue().set(key, value, time, TimeUnit.MINUTES);
				return confOrderChannel;

			} finally {
				try {
					redisLock.unlock();
				} catch (Exception ignored) {
					log.error(ignored.getMessage());
				}
			}

		} else {

			if (redisLock.lock(time, TimeUnit.SECONDS)) {
				try {
					redisLock.unlock();
				} catch (Exception ignored) {
					log.error(ignored.getMessage());
				}
				return getByChannelId(channelId);
			} else {
				log.error("根据渠道ID查询渠道订单配置，获取redis锁超时");
				throw new OmsBaseException("根据渠道ID查询渠道订单配置，获取redis锁超时");
			}

		}
	}

	private ConfOrderChannelDRO getByChannelIdDataBase(Integer channelId) {
		ConfOrderChannel confOrderChannel = confOrderChannelService.findByKey(channelId);
		if (Objects.isNull(confOrderChannel)) {
			return null;
		}
		return BeanMapper.map(confOrderChannel, ConfOrderChannelDRO.class);
	}

	@Override
	public ConfChannelWorkOrderTypeDRO getWorkOrderTypeByChannelId(Integer channelId) throws OmsBaseException {
		if (NumberUtil.isNullOrZero(channelId)) {
			throw new OmsBaseException("channelId不能为空");
		}

		ConfOrderChannel confOrderChannel = confOrderChannelService.findByKey(channelId);
		// 如果为空
		if (Objects.isNull(confOrderChannel)) {
			ChannelDRO channel = channelListRemoteService.getByChannelId(channelId).getData();

			if (Objects.equals(ChannelConsts.RANK_TWO, channel.getRank())
					&& NumberUtil.isPositiveInteger(channel.getParentId())) {
				confOrderChannel = confOrderChannelService.findByKey(channel.getParentId());
			}
		}

		ConfChannelWorkOrderTypeDRO result = new ConfChannelWorkOrderTypeDRO();
		if (Objects.nonNull(confOrderChannel)) {
			result.setWorkOrderCancelType(confOrderChannel.getWorkOrderCancelType());
			result.setWorkOrderCompleteType(confOrderChannel.getWorkOrderCompleteType());
			result.setWorkOrderSpecialOfferType(confOrderChannel.getWorkOrderSpecialOfferType());
		}

		return result;
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public void modifyOrderConfig(ConfOrderChannel channelOrderConfig) {
		ConfOrderChannel confOrderChannel = confOrderChannelService.findByKey(channelOrderConfig.getChannelId());
		String operator = StaffAdminService.currentStaff().getRealName();
		Date now = DateUtil.getNow();
		if (Objects.isNull(confOrderChannel)) {
			channelOrderConfig.setCreater(operator);
			channelOrderConfig.setCreateTime(now);
			channelOrderConfig.setUpdater(operator);
			channelOrderConfig.setUpdateTime(now);
			confOrderChannelService.insert(channelOrderConfig);
		} else {
			channelOrderConfig.setUpdater(operator);
			channelOrderConfig.setUpdateTime(now);
			confOrderChannelService.updateByKey(channelOrderConfig);

			String key = String.format(RedisKeyConsts.ORDER_CHANNEL_CONFIG_KEY, confOrderChannel.getChannelId());
			redisTemplate.delete(key);
		}
	}

	/**
	 * 根据渠道名称来获取渠道id集合
	 *
	 * @param query
	 * @return
	 * @author liudi
	 * @since: 2022/2/21 11:12
	 */
	private List<Integer> getChannelIdsByChannelName(ConfOrderChannelQuery query) {
		ChannelQuery channelQuery = new ChannelQuery();
		channelQuery.setName(query.getChannelName());
		ResponseDTO<List<ChannelDRO>> listResponseDTO = channelListRemoteService.listByQuery(channelQuery);

		if (!listResponseDTO.isSuccess() || CollectionUtils.isEmpty(listResponseDTO.getData())) {
			return Lists.newArrayList();
		} else {
			return listResponseDTO.getData().stream().map(ChannelDRO::getChannelId).collect(Collectors.toList());
		}
	}
}
